<?php

namespace App\Providers;

use Afosto\Acme\Client;
use App\Admin\Livewire\CleanCache;
use App\Admin\Livewire\Notifications;
use App\Enums\DomainType;
use App\Extends\Oss\OssAdapter;
use App\Models\DomainPool;
use App\Models\Guide;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ServiceProvider;
use Intervention\Image\ImageManager;
use Laravel\Horizon\MasterSupervisor;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use Livewire\Livewire;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        MasterSupervisor::determineNameUsing(function () {
            return config('custom.server_id');
        });

        $this->app->bind(ImageManager::class, function () {
            return app('image');
        });

        $this->app->singleton('acme', function (Application $application) {
            $adapter = new LocalFilesystemAdapter(storage_path('app'));
            $filesystem = new Filesystem($adapter);

            return new Client([
                'username' => 'jason.chen@gmail.com',
                'fs' => $filesystem,
                'mode' => Client::MODE_LIVE,
            ]);
        });
    }

    public function boot(): void
    {
        Storage::extend('oss', function (Application $application, array $config) {
            $adapter = new OssAdapter($config['config'], $config['bucket']);

            return new FilesystemAdapter(new Filesystem($adapter), $adapter);
        });

        $this->bootBlueprint();
        if (!$this->app->runningInConsole()) {
            $this->bootAdminLivewire();
            $this->bootMiddleDomains();
        }
    }

    private function bootBlueprint(): void
    {
        Blueprint::macro('cover', function () {
            return $this->string('cover')
                ->nullable()
                ->comment('封面图片');
        });
        Blueprint::macro('pictures', function () {
            return $this->json('pictures')
                ->nullable()
                ->comment('轮播图');
        });
        Blueprint::macro('user', function () {
            return $this->unsignedBigInteger('user_id')
                ->index()
                ->comment('用户ID');
        });
        Blueprint::macro('application', function () {
            return $this->unsignedBigInteger('application_id')
                ->index()
                ->comment('应用ID');
        });
        Blueprint::macro('easyStatus', function () {
            return $this->boolean('status')
                ->default(0)
                ->index();
        });
        Blueprint::macro('attachments', function () {
            return $this->json('attachments')
                ->nullable()
                ->comment('附件');
        });
        Blueprint::macro('remark', function () {
            return $this->text('remark')
                ->nullable()
                ->comment('备注信息');
        });
    }

    private function bootAdminLivewire(): void
    {
        Livewire::component('admin.notifications', Notifications::class);
        Livewire::component('admin.clean-cache', CleanCache::class);
        Livewire::setScriptRoute(function ($handle) {
            return Route::get('/vendor/livewire/livewire.min.js', $handle);
        });
        Livewire::setUpdateRoute(function ($handle) {
            return Route::post('/components/update', $handle)
                ->middleware('web');
        });
    }

    /**
     * Notes   : 注册中转域名解析
     *
     * @Date   : 2024/8/5 下午4:45
     * @Author : <Jason.C>
     */
    private function bootMiddleDomains(): void
    {
        DomainPool::ofEnabled()->where('type', DomainType::MIDDLE)->get()->each(function (DomainPool $domain) {
            Route::domain('{slug}'.str_replace('*', '', $domain->domain))
                ->get('', function (Request $request, string $slug) use ($domain) {
                    $guide = Guide::where('slug', $slug)->firstOrFail();
                    $player = $guide->player;

                    return redirect()->away($player->getPlayerUrl());
                });
        });
    }
}
